package SecondeStage.MianXiangDuiXiang.AbstractClass.InnerClass;

public class NiMingInnerClass {
    public static void main(String[] args) {
        Outer03 outer03 =new Outer03();
        outer03.method();

        Outer04 outer04 =new Outer04();
        outer04.f1();

        // 外部其他类不能访问匿名内部类
    }
}

class Outer03{
    private int n1=10;

    public void method(){
        // 基于接口的匿名内部类：
        // 1. 需求： 想使用IA接口，并创建对象
        // 2. 传统方法：写一个类，实现该接口并创建对象
        // 3. 但如果 Tiger/Dog 类只使用一次，专门写一个类就有些麻烦
        // 4. 可以使用匿名内部类来简化开发
        IA tiger =new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫....");
            }
        };

        tiger.cry();
        // tiget的编译类型是IA，运行类型是匿名内部类
        System.out.println("tiger的运行类型是: "+tiger.getClass());
        /*
        底层代码是: 类名是系统分配的-Outer03$1
            class XXXX implements IA{
                @Override
                public void cry() {
                    System.out.println("老虎叫....");
                 }
            }
         */

        // jdk底层在创建匿名内部类Outer03$1时，立马创建了Outer03$1实例，并且把地址返回给了tiger
        // 匿名内部类只能使用一次，但返回的对象tiger可以多次使用


        //基于类的匿名内部类
        // father的编译类型:Father, 运行类型:匿名内部类 Outer03$2
        Father father = new Father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father的运行类型是: "+father.getClass());
        father.test();

        //基于抽象类的匿名内部类
        Animal animal = new Animal(){
            // 抽象类必须实现抽象方法
            @Override
            void eat() {
                System.out.println("小七吃冻干");
            }
        };
        animal.eat();
    }
}

class Outer04{
    private int n1 =99;
    public void f1(){
        // 不能添加访问修饰符，因为它的地位是一个局部变量
        // 同样的，作用域仅在定义它的方法中
        person p = new person(){
            private int n1 =88;
            @Override
            public void hi() {
                // 可以直接访问外部类的所有成员，包含私有的
                // 如果外部类和内部类的成员重名时，默认遵循就近原则，如果想要访问外部类的成员，使用 外部类名.this.成员 去访问
                System.out.println("n1= "+n1 + "  外部类的n1= "+ Outer04.this.n1);
                System.out.println("匿名内部类重写了 hi方法");
            }

        };
        p.hi();
        // p的运行类型是匿名内部类，按照动态绑定机制，调用的是匿名内部类的hi方法
        System.out.println("--------------------------------");
        // 也可以直接调用
        new person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了 hi方法,哈哈哈");
            }
        }.hi();
    }
}

interface IA{
    public void cry();
}

class Father{
    private String name;

    public Father(String name) {
        this.name = name;
    }

    public void test(){

    }
}

abstract class Animal{
    abstract void eat();
}

class person{
    public void hi(){
        System.out.println("person hi()");
    }

}